<?php
ini_set('display_errors',1);
error_reporting(E_ALL);

include_once  '../conf.php';
include_once 'db.php';
include_once 'user.php';

include_once '../socket/Log.php';
include_once '../socket/connection.php';
include_once '../socket/packetStream.php';
include_once '../socket/socketServer.php';

include_once 'socketUser.php';

class Server extends SocketServer {
	public $server_users = array(); // список всех юзеров
	public $server_opened = true;
	public $server_min_users = 2;
	public $server_id = 1;
	public $server_port = 30001;
	public $server_name = 'тестовая комната';
	public $server_min_xp = 1;


	public $open_time;
	public $start_time;


	public $platform_winner;

	public $platforms = array();
	public $overtime = false; // true - игра закончена
	public $overtime_start; // true - игра закончена

	private $_lastStepTime = null;

	// стартуем игру
	public function init() {
		$start_time = time()+60*3;
		$period = 60*3;
		$this->open_time = time();
		$query = 'INSERT INTO `rooms` SET
`id` = '.$this->server_id.',
`name`=\''.mysql_escape_string($this->server_name).'\',
`host`=\'\',
`port`='.$this->server_port.',
`start`='.$start_time.',
`period`='.$period.',
`min_xp`='.$this->server_min_xp.',
`opened`=1,
`user_count`=0
	ON DUPLICATE KEY UPDATE
`id` = '.$this->server_id.',
`name`=\''.mysql_escape_string($this->server_name).'\',
`host`=\'\',
`port`='.$this->server_port.',
`start`='.$start_time.',
`period`='.$period.',
`min_xp`='.$this->server_min_xp.',
`opened`=1,
`user_count`=0';
		$r = _database::query($query);
		if($r) {
			$this->server_opened = true;
			$this->open_time = time();
			$this->start_time = $start_time;
			Log::notice('setting timer');
			$this->registerTimer(0.5, array($this, 'checkForGameStart'));
			$this->start();
			
		}
		else die('db');
	}

	// начинаем игру
	public function game_start() {
	// нельзя коннектится
		$this->server_opened = false;
		// а достаточно игроков?
		$users_count = count($this->server_users);
		if($users_count < $this->server_min_users) {
			echo 'not enough users:'.$users_count."\n";
			return false;
		}

		$this->set_team_balance($users_count);

		$this->platforms = array(
			SocketUser::PLATFORM_LEFT => array(
				'y' => conf::$platform_y,
				'minX' => -(conf::$platform_width + conf::$platform_space),
				'maxX' => -conf::$platform_space,
				'dy' => 0
			),
			SocketUser::PLATFORM_RIGHT => array(
				'y' => conf::$platform_y,
				'minX' => conf::$platform_space,
				'maxX' => conf::$platform_width + conf::$platform_space,
				'dy' => 0
			)
		);
		$this->registerTimer(0.1, array($this, 'doStep'));
		$this->registerTimer(0.1, array($this, 'sendAllStates'));
		
	}

	public function checkForGameStart()
	{
		if(!$this->server_opened) return;
		log::notice('checkForGameStart');
		$usercount = count($this->server_users);
		if($usercount > 2 && $this->start_time < time() ||  ($usercount >= $this->server_min_users))
		{
			$this->game_start();
			Log::notice('game starting!');
		}
		else
		Log::notice('time to start:'.($this->start_time-time()));
		Log::notice('usercount:'.($usercount));
	}

	// раскидываем всех
	protected function set_team_balance($users_count) {
		$half = ceil($users_count/2);
		$i = 0;
		foreach($this->server_users as $user) {
			$this->setStartingPosition($user,$i <= $half);
		}
	}

	// ставим юзера на девые или правые весы
	public function setStartingPosition($user,$is_left = false) {
		if($is_left) {
			$user->x = rand($this->platforms[SocketUser::PLATFORM_LEFT]['minX']+conf::$player_width,
				$this->platforms[SocketUser::PLATFORM_LEFT]['maxX']-conf::$player_width);
		}
		else {
			$user->x = rand($this->platforms[SocketUser::PLATFORM_RIGHT]['minX']+conf::$player_width,
				$this->platforms[SocketUser::PLATFORM_RIGHT]['maxX']-conf::$player_width);
		}

		$user->y = conf::$platform_y;
	}

	public function finish($platform_falled_id)
	{
		$this->overtime = true;
		$this->overtime_start = true;
		$this->platform_winner =
		($platform_falled_id == socketUser::PLATFORM_LEFT)?socketUser::PLATFORM_RIGHT:
		socketUser::PLATFORM_LEFT;
	}

	public function platformFalled($platform_id){
		foreach($this->clients as $user)
		{
			if($user->platform == $platform_id)
			{
				$user->fall();
			}
		}
		$this->finish($platform_id);
	}

	// конец игры
	public function shutdown() {
		foreach($this->server_users as $user)
		{
			if($user->platform == $this->platform_winner)
			{
				// добавляем ништяков
				$user->user->AddMoney(conf::$round_money);
				$user->user->AddExp(conf::$round_money);
				$user->sendPacket(array('money'=>$user->user->data['money'],'exp'=>$user->user->data['exp']));
				$user->user->save();
			}
		}
	}

	public function sendToAll($data)
	{
		foreach($this->server_users as $user)
		{
			$user->sendPacket($data);
		}
	}

	public function addUser($socket) {
		$user = new socketUser($socket,$this);
		$this->server_users[] = $user;
		
		return $user;
	}

	// принимаю или не принимаю коннект
	public function  onConnection($socket) {
		$user = $this->addUser($socket);
		if($this->server_opened) return $user;
	}

	public function doStep() {
		$now = microtime();
		if(is_null($this->_lastStepTime))
			$this->_lastStepTime = $now;

		$interval = $now - $this->_lastStepTime;
		if(!$interval)
			return;

		foreach($this->clients as $c) {
			if($c->state == socketUser::STATE_SPECTATOR)
				continue;

			$c->move($interval);
			if($c->y > 0) { // ещё не упали :)
				if($c->state == SocketUser::STATE_JUMP) {
					if($c->dy > 0)
						continue;

					foreach($this->platforms as $id=>$p) {
						if($c->y >= $p['y'] && $c->y + $c->dy <= $p['y']) { // приземлился
							$c->land($id);
							continue 2;
						}
					}
				} elseif($c->state == SocketUser::STATE_NORMAL) {
					$p = $this->platforms[$c->platform];
					if(($c->x + conf::$player_width/2) < $p['minX'] || ($c->x - conf::$platform_width/2) > $p['maxX']) {
						$c->stumble();
						continue;
					}
				}
			} else {
				$c->fall();
			}
		}

		/* рассчитываем кто на каких платформах */
		$platformBalance = 0;
		$numUsers = 0;

		foreach($this->clients as $c) {
			if($c->state == SocketUser::STATE_SPECTATOR)
				continue;

			$numUsers++;

			if(!$c->platform)
				continue;

			if($c->platform == socketUser::PLATFORM_LEFT)
				$platformBalance--;
			else
				$platformBalance++;
		}

		if(!$numUsers) {
			Log::warning('Game end?');
			return;
		}

		$platformSpeed = abs(conf::$platform_falling_speed * ($platformBalance/$numUsers));
		$platformSpeed *= $interval;

		if(!$this->overtime) {
			$falled = false;

			foreach($this->platforms as $id=>$p) {
				if($p['y'] < 0) {
					$this->platformFalled($id);
					$falled = true;
				}
			}

			if(!$falled) {
				if($numUsers > 0) { // left down
					$this->platforms[SocketUser::PLATFORM_LEFT]['y'] -= $platformSpeed;
					$this->platforms[SocketUser::PLATFORM_RIGHT]['y'] += $platformSpeed;
					$this->platforms[SocketUser::PLATFORM_LEFT]['dy'] = -$platformSpeed;
					$this->platforms[SocketUser::PLATFORM_RIGHT]['dy'] = $platformSpeed;
				} else { // right down
					$this->platforms[SocketUser::PLATFORM_RIGHT]['y'] -= $platformSpeed;
					$this->platforms[SocketUser::PLATFORM_LEFT]['y'] += $platformSpeed;
					$this->platforms[SocketUser::PLATFORM_RIGHT]['dy'] = -$platformSpeed;
					$this->platforms[SocketUser::PLATFORM_LEFT]['dy'] = $platformSpeed;
				}
			}
		} else {
			if(microtime(true) - $this->overtime_start > conf::$overtime_period)
				$this->shutdown();
		}
	}

	public function sendAllStates() {
		if(!$this->clients)
			return;
		
		$state = array(
			'type' => 'allStates',
			'platforms' => array(
				'left' => $this->platforms[SocketUser::PLATFORM_LEFT],
				'right' => $this->platforms[SocketUser::PLATFORM_RIGHT],
			),
			'clients' => array()
		);

		foreach($this->clients as $c) {
			if($c->state != SocketUser::STATE_SPECTATOR)
				continue;

			$pl = null;
			if($c->platform == socketUser::PLATFORM_LEFT)
				$pl = 'left';
			else
				$pl = 'right';
			
			$state['clients'][] = array(
				'id' => $c->user->user_id,
				'x' => $c->x,
				'y' => $c->y,
				'dx' => $c->dx,
				'dy' => $c->dy,
				'platform' => $pl
			);
		}

		foreach($this->clients as $c) {
			$c->sendPacket(
				$state
			);
		}
	}
}

$server = new Server('0.0.0.0',30001);
$server->init();
